package com.func.boom.utils.jwt;

import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Yulei
 * @Description : JWT工具类
 * <br/>参考官网：https://jwt.io/
 * <br/>JWT的数据结构为：A.B.C三部分数据，由字符点"."分割成三部分数据
 * <br/>A-header头信息
 * <br/>B-payload 有效负荷 一般包括：已注册信息（registered claims），公开数据(public claims)，私有数据(private claims)
 * <br/>C-signature 签名信息 是将header和payload进行加密生成的
 * @date  2020-09-09 23:28:36
 */
@Slf4j
public class JwtHelper {

    /**
     * @Description      生成JWT字符串
     * @param userId     用户编号
     * @param userName   用户名
     */
    public static String generateJWT(String userId, String userName) {
        //签名算法，选择SHA-256
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        //获取当前系统时间
        long nowTimeMillis = System.currentTimeMillis();
        Date now = new Date(nowTimeMillis);
        //将BASE64SECRET常量字符串使用base64解码成字节数组
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SecretConstant.BASE64SECRET);
        //使用HmacSHA256签名算法生成一个HS256的签名秘钥Key
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        //添加构成JWT的参数
        Map<String, Object> headMap = new HashMap<String, Object>(){{
            put("alg", SignatureAlgorithm.HS256.getValue());
            put("typ", "JWT");
        }};
        JwtBuilder builder = Jwts.builder().setHeader(headMap)
                //加密后的客户编号
                .claim("userId", userId)
                //客户名称
                .claim("userName", userName)
                //Signature
                .signWith(signatureAlgorithm, signingKey);
        //添加Token过期时间
        if (SecretConstant.EXPIRESSECOND >= 0) {
            long expMillis = nowTimeMillis + SecretConstant.EXPIRESSECOND;
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate).setNotBefore(now);
        }
        return builder.compact();
    }

    /**
     * @Description 解析JWT
     * @param jsonWebToken  页面传过来的token
     * @return Claims对象
     */
    public static Claims parseJWT(String jsonWebToken) {
        Claims claims = null;
        try {
            if (StringUtils.isNotBlank(jsonWebToken)) {
                //解析jwt
                claims = Jwts.parser()
                        .setSigningKey(DatatypeConverter.parseBase64Binary(SecretConstant.BASE64SECRET))
                        .parseClaimsJws(jsonWebToken)
                        .getBody();
            } else {
                log.warn("[JWTHelper]-json web token 为空");
            }
        } catch (Exception e) {
            log.error("[JWTHelper]-JWT解析异常：可能因为token已经超时或非法token");
        }
        return claims;
    }

    /**
     * @Description: 校验JWT是否有效
     * @param jsonWebToken  页面传过来的token
     * @return json字符串的demo:<br/> {"freshToken":"A.B.C","userName":"Judy","userId":"123"}
     */
    public static String validateLogin(String jsonWebToken) {
        Map<String, Object> retMap = null;
        Claims claims = parseJWT(jsonWebToken);
        if (claims != null) {
            //解密客户编号
            retMap = new HashMap<String, Object>(){{
                put("userId", claims.get("userId")); //加密后的客户编号
                put("userName", claims.get("userName")); //用户名
            }};
            //刷新JWT
            retMap.put("freshToken", generateJWT((String) claims.get("userId"), (String) claims.get("userName")));
        } else {
            log.warn("[JWTHelper]-JWT解析出claims为空");
        }
        return retMap != null ? JSONObject.toJSONString(retMap) : null;
    }

    public static void main(String[] args) throws InterruptedException {
        String jsonWebKey = generateJWT("123", "Judy");
        System.out.println(jsonWebKey);
        Claims claims = parseJWT(jsonWebKey);
        System.out.println(claims);
        System.out.println(validateLogin(jsonWebKey));

    }


}

